/*
 * Vec3.h
 *
 *  Created on: 21.09.2009
 *      Author: Christoph Caks
 */

#ifndef Vec3_H_
#define Vec3_H_

// includes
#include "System.h"
#include "math/Math.h"
#include "types/Vec2.h"

// for isnan() function
#include <math.h>

namespace mehari {
namespace common {

template <typename Real>
class Vec3 {
public:
	// constructors
	Vec3();
	Vec3( const Vec2<Real>& v2V, const Real rZ );
	Vec3( const Real x, const Real y, const Real z );
	Vec3( const Vec3<Real>& v );

	~Vec3();

	// access
	Real x() const;
	Real& x();
	Real y() const;
	Real& y();
	Real z() const;
	Real& z();
	const Real operator [] ( int iIndex ) const;
	Real& operator [] ( int iIndex );

	// arithmetic operations
	Vec3<Real> operator + ( const Vec3<Real>& vRhs ) const;
	Vec3<Real> operator - ( const Vec3<Real>& vRhs ) const;
	Vec3<Real> operator * ( const Real rRhs ) const;
	Vec3<Real> operator / ( const Real rRhs ) const;
	Vec3<Real> operator - () const;
	Real operator * ( const Vec3<Real>& vRhs ) const;

	Vec3<Real> operator += ( const Vec3<Real>& vRhs );
	Vec3<Real> operator -= ( const Vec3<Real>& vRhs );
	Vec3<Real> operator *= ( const Real rRhs );
	Vec3<Real> operator /= ( const Real rRhs );

	// comparison operations
	bool operator == ( const Vec3<Real>& vRhs) const;
	bool operator != ( const Vec3<Real>& vRhs) const;
	bool operator <  ( const Vec3<Real>& vRhs) const;
	bool operator <= ( const Vec3<Real>& vRhs) const;
	bool operator >  ( const Vec3<Real>& vRhs) const;
	bool operator >= ( const Vec3<Real>& vRhs) const;

	bool isNan() { return isnan( data[0] ) || isnan( data[1] ) || isnan( data[2] ); }

	// geometric operatons
	Real length() const;
	Real squaredLength() const;
	Real normalize();
	Real dot( const Vec3<Real>& vRhs ) const;

	// Vec3 specific
	Vec3<Real> cross( const Vec3<Real>& v3V ) const;
	Vec3<Real> unitCross( const Vec3<Real>& v3V ) const;

	static void orthonormalize( Vec3<Real>& v3V );
	static void generateOrthonormalBasis( Vec3<Real>& v3U, Vec3<Real>& v3V, Vec3<Real>& v3W, bool bUnitLengthW );

	// backwards compatibility
	Vec3<Real> operator ^ ( const Vec3<Real>& v3Rhs ) {
		return cross( v3Rhs );
	}
	Real length2() const { return squaredLength(); }
	void set( const Real x, const Real y, const Real z ) { data[0] = x; data[1] = y; data[2] = z; }
private:
	/**
	 * holds the data
	 * 0
	 * 1
	 * 2
	 */
	Real data[3];

	int compareArrays( const Vec3<Real>& rkV ) const;
};

#include "../../src/types/Vec3.cpp.inl"

typedef Vec3<float> Vec3f;
typedef Vec3<double> Vec3d;
typedef Vec3<int> Vec3i;

} // namespace common
} // namespace mehari



#endif /* Vec3_H_ */
